package top.techqi.app.mcs51.usbdlk.tile

import android.graphics.Typeface
import android.text.TextPaint
import android.util.TypedValue
import androidx.annotation.CallSuper
import androidx.core.text.PrecomputedTextCompat
import androidx.core.widget.TextViewCompat
import top.techqi.app.mcs51.R
import top.techqi.app.mcs51.databinding.ItemUsbdlkUartDataBinding
import top.techqi.core.App
import top.techqi.core.util.ResUtil
import top.techqi.view.recyclerview.tile.BindHolder
import top.techqi.view.recyclerview.tile.TilePortion
import top.techqi.view.recyclerview.tile.TileRecord
import java.text.SimpleDateFormat
import java.util.Locale
import kotlin.math.min

abstract class UsbdlkUartDataPortion<
        R : UsbdlkUartDataPortion.Record,
        VH : UsbdlkUartDataPortion.Holder<R>>
    : TilePortion<VH, R>() {

    @CallSuper
    override fun onBindRecord(holder: VH, record: R) {
        val formatter = SimpleDateFormat("HH:mm:ss.SSS", Locale.ENGLISH)
        holder.binding.txtUsbdlkUartDataTime.text = formatter.format(record.time)

        holder.binding.txtUsbdlkUartDataHex.let {
            TextViewCompat.setPrecomputedText(
                it, PrecomputedTextCompat.create(
                    record.hex, TextViewCompat.getTextMetricsParams(it)
                )
            )
        }
        holder.binding.txtUsbdlkUartDataAsc.let {
            TextViewCompat.setPrecomputedText(
                it, PrecomputedTextCompat.create(
                    record.asc, TextViewCompat.getTextMetricsParams(it)
                )
            )
        }
    }

    abstract class Record(
        val time: Long,
        val hex: CharSequence,
        val asc: CharSequence
    ) : TileRecord {
        override val index: Any = time
    }

    abstract class Holder<R : Record>(binding: ItemUsbdlkUartDataBinding) :
        BindHolder<R, ItemUsbdlkUartDataBinding>(binding) {
        init {
            binding.txtUsbdlkUartDataHex.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
            binding.txtUsbdlkUartDataAsc.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
        }
    }

    companion object {
        private val textSize: Float = precalculateTextSize()
        private fun precalculateTextSize(): Float {
            val textPaint = TextPaint()
            textPaint.setTypeface(Typeface.MONOSPACE)

            val calc: (Float, Int, Int) -> Float = { width, total, count ->
                val purview = width * count / total
                var minimum = 0f
                var maximum = purview
                var current = 0f
                var measure = 0f
                do {
                    current = (minimum + maximum) / 2
                    textPaint.textSize = current
                    measure = textPaint.measureText(" ") * count
                    if (measure > purview) {
                        maximum = current
                    } else if (measure < purview) {
                        minimum = current
                    } else {
                        break
                    }
                } while ((maximum - minimum > 0.1) && ((measure > purview) || (purview - measure > 5)))
                current
            }

            val metrics = App.INSTANCE.resources.displayMetrics
            var purview = metrics.widthPixels.toFloat()
            purview -= 2 * ResUtil.getDimensionPixelSize(R.dimen.main_usbdlk_uart_data_padding)
            purview -= 2 * ResUtil.getDimensionPixelSize(R.dimen.main_usbdlk_uart_data_divider)
            return min(calc(purview, 31, 23), calc(purview, 31, 8))
        }
    }
}
